﻿using System;
using CI.Interfaces;
using System.Runtime.Serialization;
using CI.Organism;
using CI.Utils;

namespace CI.Mesopotamia
{
    /// <summary>
    /// Survival of the fattest simulation, make sure their is not only not just neural or not neural orgs left,ISimulation
    /// </summary>
    [DataContract]
    public class SurvivalFattest : SimpleSimulationRestrictions
    {
        #region private varibles
        // the last system hearbeat we checked secondary checks
        private UInt32 _lastSysHBCheck;
        #endregion

        /// <summary>
        /// Check and apply any restrictions to the simulation that should apply, eg within max entitys, not just seeds, neural or non neural existing
        /// </summary>
        public override void RestrictionChecking(IHostingEnvironment hostingEnvironment)
        {
            #region Argument Validators
            if (hostingEnvironment == null)
                throw new ArgumentException("hostingEnvironment");
            #endregion
            // we only want one thread checking the restrictions and trimming at once else we could end up in trouble
            lock (this)
            {
                SimEnv.TraceLogger.LogDebug(string.Format("Starting - Restriction Checking"));

                base.RestrictionChecking(hostingEnvironment);

                // secondary checks only need to be done once per heartbeat
                if (hostingEnvironment.SystemHeartBeat != _lastSysHBCheck)
                {
                    // save sys hearbeat check
                    _lastSysHBCheck = hostingEnvironment.SystemHeartBeat;

                    // check and make sure their not just neural or non neural orgs in environment
                    CheckNeuralAndNonNeuralEntitys(hostingEnvironment);

                }

                SimEnv.TraceLogger.LogDebug(string.Format("Finishing - Restriction Checking"));
            }
        }

        /// <summary>
        /// Check and make sure their are not only just neural entitys or non neural entits
        /// </summary>
        private void CheckNeuralAndNonNeuralEntitys(IHostingEnvironment hostingEnvironment)
        {
            lock (this)
            {
                NeuralAliveList.Clear();
                NeuralAliveList.AddRange(hostingEnvironment.Organisms.Alive);

                // count of neural objects alive
                int neuralCount = 0;
                int nonNeuralCount = 0;

                // count the number neural objects
                foreach (IOrganism organism in NeuralAliveList)
                {
                    if (organism.NeuralSystem != null)
                        neuralCount++;
                    else
                        nonNeuralCount++;
                }

                // also check and make sure their are still alive organisms with neural activity else shut it down
                if ((neuralCount == 0) || (nonNeuralCount == 0))
                {
#if DEBUG
                    if (neuralCount == 0)
                        SimEnv.TraceLogger.LogDebug("No alive organisms with Neural activity shutting down scenario");
                    if (nonNeuralCount == 0)
                        SimEnv.TraceLogger.LogDebug("No alive organisms with NON Neural activity shutting down scenario");
#endif
                    SimEnv.TriggerScenarioRestart("No alive organisms, shutting down scenario");
                }
            }
        }
    }
}
